package com.union.vehicleassistant.util;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.text.format.DateUtils;

import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import androidx.lifecycle.LifecycleOwner;

import com.hjq.http.EasyHttp;
import com.hjq.http.model.HttpMethod;
import com.hjq.http.request.DownloadRequest;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.util.List;
import java.util.Objects;

public class FileManager {
    private static boolean isLocalStorageDocument(Context cxt, Uri uri) {
        return getFileProvider(cxt).equals(uri.getAuthority());
    }

    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getAuthority());
    }

    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getAuthority());
    }

    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getAuthority());
    }

    /**
     * 获取FileProvider path
     */
    private static String getFilePathByFileProviderUri(Context context, Uri uri) {
        try {
            List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
            String fileProviderClassName = FileProvider.class.getName();
            for (PackageInfo pack : packs) {
                ProviderInfo[] providers = pack.providers;
                if (providers != null) {
                    for (ProviderInfo provider : providers) {
                        if (Objects.equals(uri.getAuthority(), provider.authority)) {
                            if (provider.name.equalsIgnoreCase(fileProviderClassName)) {
                                Class<FileProvider> fileProviderClass = FileProvider.class;
                                try {
                                    Method getPathStrategy = fileProviderClass.getDeclaredMethod("getPathStrategy", Context.class, String.class);
                                    getPathStrategy.setAccessible(true);
                                    Object invoke = getPathStrategy.invoke(null, context, uri.getAuthority());
                                    if (invoke != null) {
                                        String PathStrategyStringClass = FileProvider.class.getName() + "$PathStrategy";
                                        Class<?> PathStrategy = Class.forName(PathStrategyStringClass);
                                        Method getFileForUri = PathStrategy.getDeclaredMethod("getFileForUri", Uri.class);
                                        getFileForUri.setAccessible(true);
                                        Object invoke1 = getFileForUri.invoke(invoke, uri);
                                        if (invoke1 instanceof File) {
                                            return ((File) invoke1).getAbsolutePath();
                                        }
                                    }
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                                break;
                            }
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Get the value of the data column for this Uri. This is useful for
     * MediaStore Uris, and other file-based ContentProviders.
     *
     * @param context       The context.
     * @param uri           The Uri to query.
     * @param selection     (Optional) Filter used in the query.
     * @param selectionArgs (Optional) Selection arguments used in the query.
     * @return The value of the _data column, which is typically a file path.
     */
    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        String column = "_data";
        String[] projection = {column};
        try (Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                int column_index = cursor.getColumnIndexOrThrow(column);
                return cursor.getString(column_index);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    // endregion

    /**
     * 由Uri读取路径
     *
     * @param context 上下文
     * @param uri     文件uri
     * @return 路径
     */
    public static String getFilePathByUri(Context context, Uri uri) {
        if (context == null || uri == null) return null;
        // 先了直接查一遍该uri，能拿到路径就不用做后续那些复杂的判断
        String filePath = getDataColumn(context, uri, null, null);
        if (!TextUtils.isEmpty(filePath))
            return filePath;

        try {
            if (isLocalStorageDocument(context, uri)) {
                // The path is the id
                filePath = getFilePathByFileProviderUri(context, uri);
            } else if (DocumentsContract.isDocumentUri(context, uri)) { // DocumentProvider
                // ExternalStorageProvider
                if (isExternalStorageDocument(uri)) {
                    String docId = DocumentsContract.getDocumentId(uri);
                    String[] split = docId.split(":");
                    String type = split[0];

                    if ("primary".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    } else if ("home".equalsIgnoreCase(type)) {
                        filePath = Environment.getExternalStorageDirectory() + "/" + split[1];
                    }
                } else if (isDownloadsDocument(uri)) { // DownloadsProvider
                    String id = DocumentsContract.getDocumentId(uri);
                    if (id.startsWith("raw:")) {
                        filePath = id.replaceFirst("raw:", "");
                    } else {
                        String[] split = id.split(":");
                        if (split.length == 2)
                            id = split[1];
                        Uri contentUri = ContentUris.withAppendedId(
                                Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));

                        filePath = getDataColumn(context, contentUri, null, null);
                    }
                } else if (isMediaDocument(uri)) { // MediaProvider
                    String docId = DocumentsContract.getDocumentId(uri);
                    String[] split = docId.split(":");
                    String type = split[0];

                    Uri contentUri = null;
                    if ("image".equals(type)) {
                        contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
                    } else if ("video".equals(type)) {
                        contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                    } else if ("audio".equals(type)) {
                        contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
                    } else {
                        try {
                            // content://com.android.providers.media.documents/document/document%3A1000002873
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                                contentUri = MediaStore.getMediaUri(context, uri);
                                filePath = getDataColumn(context, contentUri, null, null);
                            }
                        } catch (Exception ignored) {
                        }
                        try {
                            // 这个先写着适配，目前还没发现会走到这里的uri
                            if (TextUtils.isEmpty(filePath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                                contentUri = MediaStore.getDocumentUri(context, uri);
                                filePath = getDataColumn(context, contentUri, null, null);
                            }
                        } catch (Exception ignored) {
                        }
                        if (TextUtils.isEmpty(filePath))
                            contentUri = MediaStore.Files.getContentUri("external");
                    }
                    if (TextUtils.isEmpty(filePath)) {
                        String selection = "_id=?";
                        String[] selectionArgs = new String[]{split[1]};

                        filePath = getDataColumn(context, contentUri, selection, selectionArgs);
                    }
                }
            } else if ("content".equalsIgnoreCase(uri.getScheme())) { // MediaStore (and general)
                filePath = getDataColumn(context, uri, null, null);
            } else if ("file".equalsIgnoreCase(uri.getScheme())) { // File
                filePath = uri.getPath();
            }
        } catch (Exception ignored) {
        }
        if (TextUtils.isEmpty(filePath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
            filePath = uriToFileApiQ(context, uri);
        if (!TextUtils.isEmpty(filePath)) {
            String dirPath = filePath;
            if (Objects.requireNonNull(filePath).contains("/")) {
                dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
            }
            // 创建文件夹
            boolean mkdirs = new File(dirPath).mkdirs();
        }
        return filePath;
    }

    /**
     * Android 10 以上适配 :
     * 通过正常方式读取不到path，则先拷贝到私有目录，之后返回路径
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private static String uriToFileApiQ(Context context, Uri uri) {
        if (uri.getScheme() == null) return null;
        File file = null;
        //android10以上转换
        if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
            if (uri.getPath() == null)
                return null;
            file = new File(uri.getPath());
        } else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
            //把文件复制到沙盒目录
            ContentResolver contentResolver = context.getContentResolver();
            Cursor cursor = contentResolver.query(uri, null, null, null, null);
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    @SuppressLint("Range") String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
                    try {
                        InputStream is = contentResolver.openInputStream(uri);
                        if (is != null) {
                            File cache = new File(getAppCachePath(context, "select_file"), displayName);
                            if (cache.exists()) {
                                cache.delete();
                            }
                            FileOutputStream fos = new FileOutputStream(cache);
                            FileUtils.copy(is, fos);
                            file = cache;
                            fos.close();
                            is.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                cursor.close();
            }
        }
        if (file == null)
            return null;
        else
            return file.getAbsolutePath();
    }

    public static String getFileProvider(Context context) {
        return context.getPackageName() + ".fileProvider";
    }

    // 获取缓存路径
    public static String getAppCachePath(Context context, String directory) {
        String filePath;
        if (TextUtils.isEmpty(directory))
            filePath = context.getCacheDir().getPath() + File.separator;
        else
            filePath = context.getCacheDir().getPath() + File.separator + directory + File.separator;
        createSelfDirIfNotExist(filePath);
        return filePath;
    }

    // 判断私有目录是否存在，不存在则进行创建
    private static void createSelfDirIfNotExist(String path) {
        File file = new File(path);
        if (!file.exists()) {
            boolean mkdirs = file.mkdirs();
        }
    }

    /*文件保存*/

    /**
     * 获取文件下载请求
     * 默认下载到 {@link Environment#DIRECTORY_DOWNLOADS} 公共目录+{@link Context#getPackageName()} 文件夹下面
     *
     * @param owner                生命周期实现
     * @param fileSaveRelativePath 文件相对路径
     * @param fileName             文件名
     * @return 下载请求
     */
    public static DownloadRequest getDownloadRequest(LifecycleOwner owner, String fileSaveRelativePath, String fileName) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return requestAfterQ(owner, fileSaveRelativePath, fileName);
        } else {
            return requestBelowQ(owner, fileSaveRelativePath, fileName);
        }
    }

    /**
     * Android 9 以及一下版本获取下载请求（获取文件路径）
     * 默认路径为Download{@link Environment#DIRECTORY_DOWNLOADS}文件夹
     *
     * @param lifecycleOwner       生命周期
     * @param fileSaveRelativePath 文件相对路径
     * @param fileName             文件名
     * @return 下载请求
     */
    private static DownloadRequest requestBelowQ(LifecycleOwner lifecycleOwner, String fileSaveRelativePath, String fileName) {
        File directory = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
        File file = new File(directory, Utils.getAppContext().getPackageName() + "/" + fileSaveRelativePath + fileName);
        return EasyHttp.download(lifecycleOwner)
                .method(HttpMethod.GET)
                .file(file);
    }

    /**
     * Android 9 以上版本获取下载请求（获取文件路径）
     * 默认路径为Download{@link Environment#DIRECTORY_DOWNLOADS}文件夹
     *
     * @param lifecycleOwner       生命周期
     * @param fileSaveRelativePath 文件相对路径
     * @param fileName             文件名
     * @return 下载请求
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private static DownloadRequest requestAfterQ(LifecycleOwner lifecycleOwner, String fileSaveRelativePath, String fileName) {
        if (lifecycleOwner instanceof Context) {
            ContentResolver resolver = ((Context) lifecycleOwner).getContentResolver();
            ContentValues values = new ContentValues();
            values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName);
            values.put(MediaStore.MediaColumns.RELATIVE_PATH, "Download/" + Utils.getAppContext().getPackageName() + "/" + fileSaveRelativePath);
            Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
            return EasyHttp.download(lifecycleOwner)
                    .method(HttpMethod.GET)
                    .file(resolver, uri);
        }
        return null;
    }


    public static boolean isSaveImage(Context context, Bitmap bm, String name) {
        boolean isSave;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            //大于等于android 10
            isSave = saveImageQ(context, bm, name);
        } else {
            isSave = saveImage(context, bm, name);
        }
        return isSave;
    }

    /**
     * 功能描述：Android 9及以下保存图片到相册
     *
     * @param context 上下文
     * @param outB    {@link Bitmap} 图片
     * @param name    显示名称
     * @return 返回存储结果
     */
    private static boolean saveImage(Context context, Bitmap outB, String name) {
        String imgName = name.isEmpty() ? String.valueOf(System.currentTimeMillis()) : name;
        //File.separator就是文件路径
        String fileName = Environment.getExternalStorageDirectory() + File.separator + Environment.DIRECTORY_DCIM
                + File.separator + "demo" + File.separator;
        try {
            File file = new File(fileName);
            if (!file.exists()) {
                boolean success = file.mkdirs();
            }
            File filePath = new File(file + "/" + imgName + ".png");
            FileOutputStream out = new FileOutputStream(filePath); //保存到本地，格式为JPEG
            if (outB.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                out.flush();
                out.close();
            }
            //刷新图库
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//高于22版本要手动授权
                // 检查该权限是否已经获取
                int i = ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
                // 权限是否已经 授权 GRANTED---授权  DINIED---拒绝
                if (i != PackageManager.PERMISSION_GRANTED) {
                    // 提示用户应该去应用设置界面手动开启权限
                } else {
                    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(filePath)));
                }
            } else {
                context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(filePath)));
            }
            return true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 功能描述：Android10及以上保存图片到相册
     *
     * @param context 上下文
     * @param image   {@link Bitmap} 图片
     * @param name    显示名称
     * @return 返回存储结果
     */
    @RequiresApi(api = Build.VERSION_CODES.Q)
    private static boolean saveImageQ(Context context, Bitmap image, String name) {
        long mImageTime = System.currentTimeMillis();
        String mImageFileName = name.isEmpty() ? String.valueOf(mImageTime) : name;
        final ContentValues values = new ContentValues();
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM
                + File.separator + "oa"); //图库(DCIM)中显示的文件夹名。
        values.put(MediaStore.MediaColumns.DISPLAY_NAME, mImageFileName);
        values.put(MediaStore.MediaColumns.MIME_TYPE, "image/png");
        values.put(MediaStore.MediaColumns.DATE_ADDED, mImageTime / 1000);
        values.put(MediaStore.MediaColumns.DATE_MODIFIED, mImageTime / 1000);
        values.put(MediaStore.MediaColumns.DATE_EXPIRES, (mImageTime + DateUtils.DAY_IN_MILLIS) / 1000);
        values.put(MediaStore.MediaColumns.IS_PENDING, 1);
        ContentResolver resolver = context.getContentResolver();
        final Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
        try {
            //写下我们文件的数据
            try (OutputStream out = resolver.openOutputStream(uri)) {
                if (!image.compress(Bitmap.CompressFormat.PNG, 100, out)) {
                    throw new IOException("Failed to compress");
                }
            }
            //一切都很顺利
            values.clear();
            values.put(MediaStore.MediaColumns.IS_PENDING, 0);
            values.putNull(MediaStore.MediaColumns.DATE_EXPIRES);
            resolver.update(uri, values, null, null);
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    public static String getMailRelativePath(int mailId) {
        return "mail/" + mailId + "/";
    }

    public static String getDocumentRelativePath(String docId) {
        return "doc/" + docId + "/";
    }

    public static String getInfoRelativePath(int infoId) {
        return "info/" + infoId + "/";
    }

    /**
     * 转换文件大小
     *
     * @param fileS 文件长度
     * @return 格式化的文件大小
     */
    public static String FormatFileSize(long fileS) {
        DecimalFormat df = new DecimalFormat("#.00");
        String fileSizeString;
        if (fileS < 1024) {
            fileSizeString = df.format((double) fileS) + "B";
        } else if (fileS < 1048576) {
            fileSizeString = df.format((double) fileS / 1024) + "KB";
        } else if (fileS < 1073741824) {
            fileSizeString = df.format((double) fileS / 1048576) + "M";
        } else {
            fileSizeString = df.format((double) fileS / 1073741824) + "G";
        }
        return fileSizeString;
    }

}
